--[[
	Copyright (C) Udorn (Blackhand)
--]]

local layoutType = "LinearLayout"
local version = 1
local YakaGui = LibStub("YakaGui", true)
local info = YakaGui:GetLayoutInfo(layoutType) 
if (info and info.version >= version) then 
	return 
end

local log = vendor.Debug:new("LinearLayout")

yaka = yaka or {}
yaka.LinearLayout = {}
yaka.LinearLayout.prototype = {}
yaka.LinearLayout.metatable = {__index = yaka.LinearLayout.prototype}

yaka.LinearLayout.info = {layoutType = layoutType, version = version}
yaka.LinearLayout.GetLayoutInfo = function()
	return yaka.LinearLayout.info
end

local function _CalcSizes(self, childs, width, height)
	local sizes = wipe(self.sizes)
	
	-- calculate base sizes
	local total = 0
	local fillers = 0
	for k,v in pairs(childs) do
		local paddingLeft, paddingRight, paddingTop, paddingBottom = v:GetPadding()
		local size
		local pad
		if (self.cfg.vertical) then
			size = v:GetMeasuredHeight(width)
			pad = paddingTop + paddingBottom
		else
			size = v:GetMeasuredWidth()
			pad = paddingLeft + paddingRight
		end
		if (size == "fill") then
			size = 0
			fillers = fillers + 1
		end
		total = total + size + pad
		table.insert(sizes, size + pad)
	end

	-- check if everything will fit
	local remaining = 0
	if (self.cfg.vertical) then
		if (height and total > height) then
			error(string.format("layout not possible, childs are too high; total [%s] height [%s]", total, height))
		end
		if (height) then
			remaining = height - total
		end
	else
		if (total > width) then
			error("layout not possible, childs are too wide")
		end
		remaining = width - total
	end
	
	-- distribute remaining space
	local off = 1
	if (fillers > 0 and remaining > 0) then
		local add = remaining / fillers
		for k,v in pairs(childs) do
			local size
			if (self.cfg.vertical) then
				size = v:GetMeasuredHeight()
			else
				size = v:GetMeasuredWidth()
			end
			if (size == "fill") then
				sizes[off] = sizes[off] + add
			end
			off = off + 1
		end
	end
end

local function _LayoutChildVertically(v, width, w, h, paddingLeft, paddingTop, xy)
	if (w < width and v:GetHorizontalAlign() == "RIGHT") then
		v:Layout(paddingLeft + (width - w), xy - paddingTop, w, h)
	elseif (w < width and v:GetHorizontalAlign() == "CENTER") then
		v:Layout(paddingLeft + (width - w) / 2, xy - paddingTop, w, h)
	else
		v:Layout(paddingLeft, xy - paddingTop, w, h)
	end
end

local function _LayoutFreeHeight(self, childs, width)
	local off = 1
	local xy = 0
	local maxH = 0
	for k, v in pairs(childs) do
	
		local size = self.sizes[off]
		off = off + 1
		
		local paddingLeft, paddingRight, paddingTop, paddingBottom = v:GetPadding()
		local w
		if (self.cfg.vertical) then
			--h = size - paddingTop - paddingBottom
			local mw = v:GetMeasuredWidth()
			if (mw == "fill") then
				w = width - paddingLeft - paddingRight
			else
				w = math.min(width - paddingLeft - paddingRight, mw)
			end
		else
			w = size - paddingLeft - paddingRight
			local mh = v:GetMeasuredHeight(width)
			if (mh == "fill") then
				error("no \"fill\" height supported in free height layout")
--			else
--				h = math.min(height - paddingTop - paddingBottom, mh)
			end
		end
		
		if (self.cfg.vertical) then
			_LayoutChildVertically(v, width, w, nil, paddingLeft, paddingTop, xy)
			xy = xy - v:GetHeight() - paddingTop - paddingBottom
		else
			v:Layout(xy + paddingLeft, -paddingTop, w)
			maxH = math.max(maxH, v:GetHeight())
			xy = xy + size
		end
	end
	if (self.cfg.vertical) then
		return math.abs(xy)
	else
		return maxH
	end
	
end

local function _Layout(self, childs, width, height)
	local off = 1
	local xy = 0
	local w, h
	for k, v in pairs(childs) do
		local size = self.sizes[off]
		local paddingLeft, paddingRight, paddingTop, paddingBottom = v:GetPadding()
		if (self.cfg.vertical) then
			h = size - paddingTop - paddingBottom
			local mw = v:GetMeasuredWidth()
			if (mw == "fill") then
				w = width - paddingLeft - paddingRight
			else
				w = math.min(width - paddingLeft - paddingRight, mw)
			end
		else
			w = size - paddingLeft - paddingRight
			local mh = v:GetMeasuredHeight(width)
			if (mh == "fill") then
				h = height - paddingTop - paddingBottom
			else
				h = math.min(height - paddingTop - paddingBottom, mh)
			end
		end
		
		if (self.cfg.vertical) then
			_LayoutChildVertically(v, width, w, h, paddingLeft, paddingTop, xy)
			xy = xy - size
		else
			v:Layout(xy + paddingLeft, -paddingTop, w, h)
			xy = xy + size
		end
		
		off = off + 1
	end
end

local function _InitCfg(self, cfgIn)
	local cfg = {}
	
	cfg.vertical = cfgIn.vertical
	
	self.cfg = cfg
end

local function _Init(self, cfgIn)
	_InitCfg(self, cfgIn)
	self.sizes = {}
end

--[[ 
	Creates a new instance.
--]]
function yaka.LinearLayout:new(cfg)
	local instance = setmetatable({}, self.metatable)
	_Init(instance, cfg)
	return instance
end

function yaka.LinearLayout.prototype:Layout(childs, width, height)
	if (#childs > 0) then
		_CalcSizes(self, childs, width, height)
		if (not height) then
			return _LayoutFreeHeight(self, childs, width)
		end
		_Layout(self, childs, width, height)
	end
end

-- register layout

YakaGui:RegisterLayoutType(yaka.LinearLayout)